﻿using OthelloGame;
using System;

namespace OthelloCognition
{
    public enum Heuristics
    {
        Mobility,
        Mobplus,
        Score,
        SmartScore,
        Stability,
        MoStSum,
        MoStMax,
        DenyStable,
        HalfStable
    }
    public abstract class AbstractHeuristic
    {
        public abstract int evaluate(OthelloGameBoard board, PieceColors player);
    }

    public static class HeuristicFactory
    {
        public static AbstractHeuristic getHeuricstic(Heuristics kind)
        {
            switch (kind)
            {
                case Heuristics.Mobility:
                    return new Mobility();
                case Heuristics.MoStMax:
                    return new MSMax();
                case Heuristics.Score:
                    return new Score();
                case Heuristics.SmartScore:
                    return new SmartScore();
                case Heuristics.Stability:
                    return new Stability();
                case Heuristics.MoStSum:
                    return new MSHeuristic();
                case Heuristics.Mobplus:
                    return new Mobility2();
                case Heuristics.HalfStable:
                    return new HalfStability();
                case Heuristics.DenyStable:
                    return new DenyStability();
                default:
                    return null;
            }


        }
    }

    public class Mobility : AbstractHeuristic
    {
        public override int evaluate(OthelloGameBoard board, PieceColors player)
        {
            return board.AvailableOptionLocations.Count;
        }
    }

    public class Mobility2 : AbstractHeuristic
    {
        public override int evaluate(OthelloGameBoard board, PieceColors player)
        {
            return (board.PlayersTurn == player ? 1 : -1) * board.AvailableOptionLocations.Count;
        }
    }

    public class Score : AbstractHeuristic
    {
        public override int evaluate(OthelloGameBoard board, PieceColors player)
        {
            return board.PitCount(player);
        }
    }

    public class SmartScore : AbstractHeuristic
    {
        public static readonly int[,] weight = new int[8,8] {{50, -1, 5, 2, 2, 5, -1, 50},
                                                {-1, -10, 1, 1, 1, 1, -1, -1},
                                                {5, 1, 1, 1, 1, 1, 1, 5},
                                                {2, 1, 1, 0, 0, 1, 1, 2},
                                                {2, 1, 1, 0, 0, 1, 1, 2},
                                                {5, 1, 1, 1, 1, 1, 1, 5},
                                                {-1, -10, 1, 1, 1, 1, -1, -1},
                                                {50, -1, 5, 2, 2, 5, -1, 50}};
        public override int evaluate(OthelloGameBoard board, PieceColors player)
        {
            int score = 0;
            for (int i = 0; i < 8; i++)
            {
                for (int j = 0; j < 8; j++)
                {
                    if (board[i, j] != null && board[i, j].PieceColor == player)
                        score += weight[i, j];
                }
            }
            return score;
        }
    }

    public class Stability : AbstractHeuristic
    {
        public override int evaluate(OthelloGameBoard board, PieceColors player)
        {
            int score = 0;
            //count fully stable
            //top left corner
            if (board[0, 0] != null)
            {
                if (board[0, 0].PieceColor == player)
                {
                    score += 2;
                    bool end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[0, i] != null && board[0, i].PieceColor == player) score++;
                        else end = true;
                    }
                    end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[i, 0] != null && board[i, 0].PieceColor == player) score++;
                        else end = true;
                    }
                }
                else
                {
                    score -= 2;
                    bool end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[0, i] != null && board[0, i].PieceColor != player) score--;
                        else end = true;
                    }
                    end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[i, 0] != null && board[i, 0].PieceColor != player) score--;
                        else end = true;
                    }
                }
            }
            // top right corner
            if (board[7, 0] != null)
            {
                if (board[7, 0].PieceColor == player)
                {
                    score += 2;
                    bool end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[7, i] != null && board[7, i].PieceColor == player) score++;
                        else end = true;
                    }
                    end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[7 - i, 0] != null && board[7 - i, 0].PieceColor == player) score++;
                        else end = true;
                    }
                }
                else
                {
                    score -= 2;
                    bool end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[7, i] != null && board[7, i].PieceColor != player) score--;
                        else end = true;
                    }
                    end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[7 - i, 0] != null && board[7 - i, 0].PieceColor != player) score--;
                        else end = true;
                    }
                }
            }
            //bottom left
            if (board[0, 7] != null)
            {
                if (board[0, 7].PieceColor == player)
                {
                    score += 2;
                    bool end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[i, 7] != null && board[i, 7].PieceColor == player) score++;
                        else end = true;
                    }
                    end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[0, 7 - i] != null && board[0, 7 - i].PieceColor == player) score++;
                        else end = true;
                    }
                }
                else
                {
                    score -= 2;
                    bool end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[i, 7] != null && board[i, 7].PieceColor != player) score--;
                        else end = true;
                    }
                    end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[0, 7 - i] != null && board[0, 7 - i].PieceColor != player) score--;
                        else end = true;
                    }
                }
            }
            //bottom right
            if (board[7, 7] != null)
            {
                if (board[7, 7].PieceColor == player)
                {
                    score += 2;
                    bool end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[7 - i, 7] != null && board[7 - i, 7].PieceColor == player) score++;
                        else end = true;
                    }
                    end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[7, 7 - i] != null && board[7, 7 - i].PieceColor == player) score++;
                        else end = true;
                    }
                }
                else
                {
                    score -= 2;
                    bool end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[7 - i, 7] != null && board[7 - i, 7].PieceColor != player) score--;
                        else end = true;
                    }
                    end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[7, 7 - i] != null && board[7, 7 - i].PieceColor != player) score--;
                        else end = true;
                    }
                }
            }
            return score;
        }
    }

    public class HalfStability : AbstractHeuristic
    {
        public override int evaluate(OthelloGameBoard board, PieceColors player)
        {
            int score = 0;
            //count fully stable
            //top left corner
            if (board[0, 0] != null)
            {
                if (board[0, 0].PieceColor == player)
                {
                    score += 2;
                    bool end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[0, i] != null && board[0, i].PieceColor == player) score++;
                        else end = true;
                    }
                    end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[i, 0] != null && board[i, 0].PieceColor == player) score++;
                        else end = true;
                    }
                }
            }
            // top right corner
            if (board[7, 0] != null)
            {
                if (board[7, 0].PieceColor == player)
                {
                    score += 2;
                    bool end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[7, i] != null && board[7, i].PieceColor == player) score++;
                        else end = true;
                    }
                    end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[7 - i, 0] != null && board[7 - i, 0].PieceColor == player) score++;
                        else end = true;
                    }
                }
            }
            //bottom left
            if (board[0, 7] != null)
            {
                if (board[0, 7].PieceColor == player)
                {
                    score += 2;
                    bool end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[i, 7] != null && board[i, 7].PieceColor == player) score++;
                        else end = true;
                    }
                    end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[0, 7 - i] != null && board[0, 7 - i].PieceColor == player) score++;
                        else end = true;
                    }
                }
            }
            //bottom right
            if (board[7, 7] != null)
            {
                if (board[7, 7].PieceColor == player)
                {
                    score += 2;
                    bool end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[7 - i, 7] != null && board[7 - i, 7].PieceColor == player) score++;
                        else end = true;
                    }
                    end = false;
                    for (int i = 0; i < 8 && !end; i++)
                    {
                        if (board[7, 7 - i] != null && board[7, 7 - i].PieceColor == player) score++;
                        else end = true;
                    }
                }
            }
            return score;
        }
    }

    public class DenyStability : AbstractHeuristic
    {
        public override int evaluate(OthelloGameBoard board, PieceColors player)
        {
            int score = 0;
            //count fully stable
            //top left corner
            if (board[0, 0] != null && board[0, 0].PieceColor != player)
            {
                score -= 2;
                bool end = false;
                for (int i = 0; i < 8 && !end; i++)
                {
                    if (board[0, i] != null && board[0, i].PieceColor != player) score--;
                    else end = true;
                }
                end = false;
                for (int i = 0; i < 8 && !end; i++)
                {
                    if (board[i, 0] != null && board[i, 0].PieceColor != player) score--;
                    else end = true;
                }
            }
            // top right corner
            if (board[7, 0] != null && board[7, 0].PieceColor != player)
            {
                score -= 2;
                bool end = false;
                for (int i = 0; i < 8 && !end; i++)
                {
                    if (board[7, i] != null && board[7, i].PieceColor != player) score--;
                    else end = true;
                }
                end = false;
                for (int i = 0; i < 8 && !end; i++)
                {
                    if (board[7 - i, 0] != null && board[7 - i, 0].PieceColor != player) score--;
                    else end = true;
                }
            }
            //bottom left
            if (board[0, 7] != null && board[0, 7].PieceColor != player)
            {
                score -= 2;
                bool end = false;
                for (int i = 0; i < 8 && !end; i++)
                {
                    if (board[i, 7] != null && board[i, 7].PieceColor != player) score--;
                    else end = true;
                }
                end = false;
                for (int i = 0; i < 8 && !end; i++)
                {
                    if (board[0, 7 - i] != null && board[0, 7 - i].PieceColor != player) score--;
                    else end = true;
                }
            }
            //bottom right
            if (board[7, 7] != null && board[7, 7].PieceColor != player)
            {
                score -= 2;
                bool end = false;
                for (int i = 0; i < 8 && !end; i++)
                {
                    if (board[7 - i, 7] != null && board[7 - i, 7].PieceColor != player) score--;
                    else end = true;
                }
                end = false;
                for (int i = 0; i < 8 && !end; i++)
                {
                    if (board[7, 7 - i] != null && board[7, 7 - i].PieceColor != player) score--;
                    else end = true;
                }
            }
            return score;
        }
    }

    public class MSHeuristic : AbstractHeuristic
    {
        private Mobility2 m;
        private Stability s;
        public MSHeuristic()
        {
            m = new Mobility2();
            s = new Stability();
        }
        public override int evaluate(OthelloGameBoard board, PieceColors player)
        {
            return m.evaluate(board, player) + s.evaluate(board, player);
        }
    }

    public class MSMax : AbstractHeuristic
    {
        private Mobility2 m;
        private Stability s;
        public MSMax()
        {
            m = new Mobility2();
            s = new Stability();
        }
        public override int evaluate(OthelloGameBoard board, PieceColors player)
        {
            return Math.Max(m.evaluate(board, player), s.evaluate(board, player));
        }
    }


}